//
// Created by 15229 on 2021/11/21.
//

#include "SyncBuffer.h"

#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>

namespace android {
    SyncBuffer::SyncBuffer(size_t size, const char *name) {
        sp<MemoryHeapBase> heap = new MemoryHeapBase(sizeof(sem_t) + size, 0, name);
        if (heap != nullptr) {
            mMem = new MemoryBase(heap, 0, heap->getSize());

            uint8_t * addr = ((uint8_t*)heap->getBase()) + heap->getOffset();
            _lock = reinterpret_cast<sem_t *>(addr);
            if (sem_init(_lock, 1, 1) < 0) {
                ALOGE("Lock init failed.");
                _lock = nullptr;
            }
        }
    }

    SyncBuffer::SyncBuffer(sp <IMemory> &mem) {
        mMem = mem;

        if (mMem != nullptr) {
            ssize_t offset;
            size_t size;
            auto heap = mMem->getMemory(&offset, &size);
            uint8_t *raw = ((uint8_t *) heap->getBase()) + offset;

            if (_lock == nullptr) {
                _lock = reinterpret_cast<sem_t *>(raw);
            }
        }
    }

    SyncBuffer::~SyncBuffer() {
        if (_lock != nullptr) {
            sem_close(_lock);
            sem_destroy(_lock);
            _lock = nullptr;
        }
    }

    bool SyncBuffer::lock() {
        if (_lock != nullptr) {
            return sem_wait(_lock) >= 0;
        }

        return false;
    }

    bool SyncBuffer::unlock() {
        if (_lock != nullptr) {
            return sem_post(_lock) >= 0;
        }
        return false;

    }

    void *SyncBuffer::addr(size_t *len) {
        if (mMem != nullptr) {
            ssize_t offset;
            size_t size;
            auto heap = mMem->getMemory(&offset, &size);
            uint8_t *raw = ((uint8_t *) heap->getBase()) + offset;

            if (_lock == nullptr) {
                _lock = reinterpret_cast<sem_t *>(raw);
            }

            size_t lock_size = sizeof(sem_t);

            if (len != nullptr) {
                *len = size - lock_size;
            }

            auto addr = raw + lock_size;
            return addr;
        }

        return nullptr;
    }

}
